<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>10马少趣多尝试!</title>
    </head>
    <body onload="main()">
        <canvas id = "canvas" width="400" height="400"></canvas>
    </body>
    <script type="text/javascript" src="lib/webgl-utils.js"></script>
    <script type="text/javascript" src="lib/m4.js"></script>
    <script type="text/javascript" src="lib/texture-utils.js"></script>
    <script type="text/javascript" src="lib/primitives.js"></script>
    <script type="text/javascript" src="lib/chroma.min.js"></script>
    <script type="text/javascript" src="lib/webgl-lessons-ui.js"></script>
    <!-- vertex shader -->
    <script  id="vertex-shader-3d" type="x-shader/x-vertex">
        uniform mat4 u_worldViewProjection;
        uniform vec3 u_lightWorldPos;
        uniform mat4 u_world;
        uniform mat4 u_viewInverse;
        uniform mat4 u_worldInverseTranspose;

        attribute vec4 a_position;
        attribute vec3 a_normal;
        attribute vec2 a_texcoord;

        varying vec4 v_position;
        varying vec2 v_texCoord;
        varying vec3 v_normal;
        varying vec3 v_surfaceToLight;
        varying vec3 v_surfaceToView;

        void main() {
          v_texCoord = a_texcoord;
          v_position = (u_worldViewProjection * a_position);
          v_normal = (u_worldInverseTranspose * vec4(a_normal, 0)).xyz;
          v_surfaceToLight = u_lightWorldPos - (u_world * a_position).xyz;
          v_surfaceToView = (u_viewInverse[3] - (u_world * a_position)).xyz;
          gl_Position = v_position;
        }
    </script>
        <!-- fragment shader -->
    <script  id="fragment-shader-3d" type="x-shader/x-fragment">
        precision mediump float;
            
        varying vec4 v_position;
        varying vec2 v_texCoord;
        varying vec3 v_normal;
        varying vec3 v_surfaceToLight;
        varying vec3 v_surfaceToView;
            
        uniform vec4 u_lightColor;
        uniform vec4 u_colorMult;
        uniform sampler2D u_diffuse;
        uniform vec4 u_specular;
        uniform float u_shininess;
        uniform float u_specularFactor;
            
        vec4 lit(float l ,float h, float m) {
            return vec4(1.0, abs(l),(l > 0.0) ? pow(max(0.0, h), m) : 0.0,1.0);
        }
            
        void main() {
            vec4 diffuseColor = texture2D(u_diffuse, v_texCoord);
            vec3 a_normal = normalize(v_normal);
            vec3 surfaceToLight = normalize(v_surfaceToLight);
            vec3 surfaceToView = normalize(v_surfaceToView);
            vec3 halfVector = normalize(surfaceToLight + surfaceToView);
            vec4 litR = lit(dot(a_normal, surfaceToLight), dot(a_normal, halfVector), u_shininess);
            vec4 outColor = vec4((u_lightColor * (diffuseColor * litR.y * u_colorMult + u_specular * litR.z * u_specularFactor)).rgb, diffuseColor.a);
            gl_FragColor = outColor;
        }
    </script>
    <script type="text/javascript" >
        function main(){

            //init gl
            var canvas = document.getElementById("canvas");
            var gl = canvas.getContext("webgl");
            if (!gl) {
                error("not supported webgl.");
                return;
            }

            gl.enable(gl.DEPTH_TEST);

            var programInfo = webglUtils.createProgramInfo(gl, ["vertex-shader-3d", "fragment-shader-3d"]);

            //属性数据，创建VBO使用
            var arrays = {
                position: { numComponents: 3, data: [0, 0, 0, 10, 0, 0, 0, 10, 0, 10, 10, 0], },
                texcoord: { numComponents: 2, data: [0, 0, 0, 1, 1, 0, 1, 1],                 },
                normal:   { numComponents: 3, data: [0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1],     },
                indices:  { numComponents: 3, data: [0, 1, 2, 1, 2, 3],                       },
            }
            //var bufferInfo = primitives.createCubeBufferInfo(gl, 10);
            var bufferInfo = webglUtils.createBufferInfoFromArrays(gl, arrays);
            // var bufferInfo = primitives.createPlaneBufferInfo(gl, 100, 100, 100, 100);
            //var bufferInfo = primitives.create3DFBufferInfo(gl);
            //var bufferInfo = primitives.createXYQuadBufferInfo(gl, 5, 0, 20);
            // var bufferInfo = primitives.createTruncatedConeBufferInfo(gl, 10, 10, 50, 50, 100);

            //相机
            var FOV = degToRad(60);

            //全局
            var uniformForAllObjects = {
                u_lightWorldPos: [-50, 30, 100],
                u_viewInverse: m4.identity(),
                u_lightColor: [1, 1, 1, 1]
            }
            var uniformForEachObject = {
                u_worldViewProjection: m4.identity(),
                u_world: m4.identity(),
                u_worldInverseTranspose: m4.identity(),
            }
            var textures = [
                textureUtils.makeStripeTexture(gl, { color1: "#FFF", color2: "#CCC", }),
                textureUtils.makeCheckerTexture(gl, { color1: "#FFF", color2: "#CCC", }),
                textureUtils.makeCircleTexture(gl, { color1: "#FFF", color2: "#CCC", }),
                // textureUtils.makeRandomTexture(gl),
            ]

            //Objects定义
            var objects = [];
            var numObjects = 100;
            var baseColor = rand(240);
            for(var ii= 0; ii < numObjects; ii++){
                objects.push({
                    radius: rand(150),
                    xRotation: rand(Math.PI * 2),
                    yRotation: rand(Math.PI),
                    materialUniforms: {
                        u_colorMult:             chroma.hsv(rand(baseColor, baseColor + 120), 0.5, 1).gl(),
                        u_diffuse:               textures[randInt(textures.length)],
                        u_specular:              [1, 1, 1, 1],
                        u_shininess:             rand(500),
                        u_specularFactor:        rand(1),
                    },
                })
            }

            requestAnimationFrame(drawScence);

            function drawScence(time){
                time = time * 0.0001 + 5;
                //console.log(time);
                webglUtils.resizeCanvasToDisplaySize(gl.canvas);
                gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
                gl.clearColor(0.0, 0.0, 0.0, 1.0);
                gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);

                var aspect = gl.canvas.clientWidth / gl.canvas.clientHeight;
                var projectionMatrix = m4.perspective(FOV, aspect, 1, 2000);

                var cameraPosotion = [0, 0, 100];
                var cameraTarget = [0, 0, 0];
                var cameraUp = [0, 1, 0];

                var cameraMatrix = m4.lookAt(cameraPosotion, cameraTarget, cameraUp, uniformForAllObjects.u_viewInverse);
                var viewMatrix = m4.inverse(cameraMatrix);
                var viewProjectionMatrix = m4.multiply(projectionMatrix, viewMatrix);
                gl.useProgram(programInfo.program);

                webglUtils.setBuffersAndAttributes(gl, programInfo, bufferInfo);
                webglUtils.setUniforms(programInfo, uniformForAllObjects);

                objects.forEach(function (item){
                    var worldMatrix = m4.xRotation(item.xRotation * time);
                    worldMatrix = m4.yRotate(worldMatrix, item.yRotation * time);
                    worldMatrix = m4.translate(worldMatrix, 0, 0, item.radius);
                    uniformForEachObject.u_world = worldMatrix;

                    m4.multiply(viewProjectionMatrix, uniformForEachObject.u_world, uniformForEachObject.u_worldViewProjection);
                    m4.transpose(m4.inverse(uniformForEachObject.u_world), uniformForEachObject.u_worldInverseTranspose);

                    webglUtils.setUniforms(programInfo, uniformForEachObject);
                    webglUtils.setUniforms(programInfo, item.materialUniforms);

                    //gl.drawElements(gl.TRIANGLES, bufferInfo.numElements, gl.UNSIGNED_SHORT, 0);///TODO!!!!!!!!!记住这里不是 UNSIGNED_BYTE
                    webglUtils.drawBufferInfo(gl, bufferInfo, gl.TRIANGLES, bufferInfo.numElements, 0, 1000);
                });

                requestAnimationFrame(drawScence);
            }
        }

        function degToRad(deg){
            return deg * Math.PI / 180.0;
        }

        function rand(min, max){
            if(!max){
                max = min;
                min = 0;
            }
            return min + Math.random() * (max - min);
        }

        function randInt(range){
            return Math.floor(Math.random() * range);
        }
    </script>
</html>